/* eslint-disable unused-imports/no-unused-vars */

import type { DependencyEnvironmentProperty } from '../../dependency/types'
import Swal from 'sweetalert2'
import { logger } from '../../../types/constants'
import { SYMBOLS } from '../../../types/interfaces'
import {
  ExternalDependency,
  getAllDependencyConfigs,
} from '../../dependency/types'

/**
 * 环境类型定义
 */
type EnvironmentType
  = | 'userscript'
    | 'browser-extension'
    | 'secure-webpage'
    | 'webpage'

/**
 * 环境信息接口
 */
interface EnvironmentInfo {
  type: EnvironmentType
  isSecure: boolean
  hasUnsafeWindow: boolean
  hasChromeAPI: boolean
  protocol: string
  userAgent: string
  extensionInfo?: ExtensionInfo | null
}

/**
 * 兼容性报告接口
 */
interface CompatibilityReport {
  isCompatible: boolean
  issues: string[]
  warnings: string[]
  environment: EnvironmentInfo
}

export type ExtensionType = 'chrome' | 'firefox' | 'edge' | 'unknown' | 'none'
/**
 * 扩展信息接口
 */
interface ExtensionInfo {
  type: ExtensionType
  id: string
  version: string
  isContentScript: boolean
  isBackgroundPage: boolean
}

/**
 * 扩展 API 调用配置
 */
interface ExtensionAPICall {
  action: 'sendMessage' | 'getURL' | 'getManifest'
  data?: any
  options?: {
    timeout?: number
  }
}

/**
 * 支持的前端框架类型枚举
 */
export enum FrameworkType {
  React = 'react',
  Vue = 'vue',
  Angular = 'angular',
  Svelte = 'svelte',
  Solid = 'solid',
}

/**
 * 环境工具类
 */
export class EnvironmentUtils {
  /**
   * 设置 jQuery 到全局 Window 对象
   */
  static setJqueryToWindow(): void {
    const scriptWindow = this.getScriptSandboxWindow()

    if (!scriptWindow)
      return

    scriptWindow.$ = scriptWindow.$ || scriptWindow.jQuery
    scriptWindow.jQuery = scriptWindow.jQuery || scriptWindow.$
  }

  /**
   * 检查指定依赖是否已加载
   * @param dep 依赖项枚举值
   * @returns 如果依赖已加载则返回 true，否则返回 false
   */
  static checkDependencyLoaded(dep: ExternalDependency): boolean {
    if (dep === ExternalDependency.JQuery)
      return this.checkJqueryLoaded()

    if (dep === ExternalDependency.SweetAlert)
      return this.checkSweetalertLoaded()

    const config = getAllDependencyConfigs()
      .find(([key]) => key === dep)

    if (!config)
      return false

    const environmentObject = this.generateDependencyEnvironmentObject(config[1].environment as DependencyEnvironmentProperty)
    return environmentObject !== undefined && environmentObject !== null
  }

  /**
   * 生成依赖环境访问对象
   */
  static generateDependencyEnvironmentObject(environment: DependencyEnvironmentProperty): any {
    if (!environment)
      return undefined

    try {
      // 获取目标窗口对象
      const namespace = 'namespace' in environment && environment.namespace ? environment.namespace : ''
      const targetWindow = this.getTargetWindowByNamespace(namespace)

      if (!targetWindow)
        return undefined

      // 安全获取嵌套属性值
      return this.getNestedPropertyValue(targetWindow, environment.property)
    }
    catch (error) {
      logger.warn(`获取环境对象失败:`, error)
      return undefined
    }
  }

  /**
   * 根据命名空间获取目标窗口对象
   */
  private static getTargetWindowByNamespace(namespace?: string): Window | any {
    switch (namespace) {
      case 'window':
        // 脚本沙箱窗口（油猴环境）
        return this.getScriptSandboxWindow()

      case 'page':
      case 'unsafe':
      case 'target':
        // 目标页面窗口
        return this.getTargetPageWindow()

      case 'global':
      case 'globalThis':
      case 'self':
        // 当前上下文
        return globalThis

      case 'parent':
        // 父窗口（iframe 环境）
        return parent

      case 'top':
        // 顶级窗口
        return top

      default:
        // 没有命名空间或自定义命名空间，默认使用页面窗口
        return this.getScriptSandboxWindow()
    }
  }

  /**
   * 获取嵌套属性值
   */
  private static getNestedPropertyValue(obj: any, property: string): any {
    let current = obj

    for (const part of property.split('.')) {
      if (current == null || current[part] === undefined) {
        return undefined
      }

      current = current[part]
    }

    return current
  }

  /**
   * 检查 jQuery 是否已加载
   */
  static checkJqueryLoaded(): boolean {
    const scriptWindow = this.getScriptSandboxWindow()

    return scriptWindow && typeof scriptWindow.jQuery !== 'undefined'
      && typeof scriptWindow.$ !== 'undefined'
      && scriptWindow.jQuery === scriptWindow.$
  }

  /**
   * 检查 SweetAlert 是否已加载
   */
  static checkSweetalertLoaded(): boolean {
    return typeof Swal !== 'undefined'
  }

  /**
   * 获取目标页面的 Window 对象（油猴脚本环境）
   * @description 在油猴脚本中安全地访问页面本身的 Window 对象
   * @returns {Window} 页面全局 Window 对象
   * @example
   * // 在油猴脚本中访问页面全局变量
   * const pageWindow = EnvironmentUtils.getTargetPageWindow();
   * const pageTitle = pageWindow.document.title;
   *
   * // 对比：访问脚本自身的 Window
   * const scriptWindow = window; // 脚本自己的 Window
   */
  static getTargetPageWindow(): Window {
    return unsafeWindow
  }

  /**
   * 获取脚本自身的 Window 对象（沙盒环境）
   * @description 获取油猴脚本运行环境的 Window 对象
   * @returns {Window} 脚本沙盒环境的 Window 对象
   * @example
   * // 访问脚本自身的全局变量
   * const scriptWindow = EnvironmentUtils.getScriptSandboxWindow();
   * scriptWindow.myScriptVar = '脚本变量';
   */
  static getScriptSandboxWindow(): Window {
    return window
  }

  /**
   * 获取页面全局的 jQuery 实例
   * @description 安全地访问页面中已加载的 jQuery 库
   * @returns {any} 页面全局 jQuery 对象，如果不存在则返回 undefined
   * @example
   * // 使用页面中的 jQuery
   * const pageJQuery = EnvironmentUtils.getTargetPageJQuery();
   * if (pageJQuery) {
   *   pageJQuery('button').click();
   * }
   */
  static getTargetPageJQuery(): any {
    const pageWindow = this.getTargetPageWindow()
    return pageWindow.jQuery || pageWindow.$
  }

  /**
   * 获取脚本沙盒环境的 jQuery 实例
   * @description 获取脚本自身引入的 jQuery 库（如果有）
   * @returns {any} 脚本沙盒环境的 jQuery 对象
   * @example
   * // 使用脚本自己的 jQuery（避免与页面冲突）
   * const scriptJQuery = EnvironmentUtils.getScriptSandboxJQuery();
   * // 如果脚本没有引入jQuery，可以动态加载
   */
  static getScriptSandboxJQuery(): any {
    const scriptWindow = this.getScriptSandboxWindow()
    return scriptWindow.jQuery || scriptWindow.$
  }

  /**
   * 检查 GM_xmlhttpRequest 是否可用
   */
  static isGMXMLHttpRequestAvailable(): boolean {
    return typeof GM_xmlhttpRequest !== 'undefined'
  }

  /**
   * 获取当前执行环境的类型
   * @description 返回详细的执行环境信息
   * @returns {EnvironmentInfo} 环境信息对象
   * @example
   * const envInfo = EnvironmentUtils.getExecutionEnvironment();
   * console.log(`运行环境: ${envInfo.type}, 是否安全: ${envInfo.isSecure}`);
   */
  static getExecutionEnvironment(): EnvironmentInfo {
    const isUserScript = this.isUserScriptEnvironment()
    const isExtension = this.isBrowserExtensionEnvironment()

    let type: EnvironmentType = 'webpage'
    let isSecure = false

    if (isUserScript) {
      type = 'userscript'
      isSecure = true // 油猴脚本有安全沙盒
    }
    else if (isExtension) {
      type = 'browser-extension'
      isSecure = true
    }
    else if (window.location.protocol === 'https:') {
      type = 'secure-webpage'
      isSecure = true
    }

    return {
      type,
      isSecure,
      hasUnsafeWindow: isUserScript,
      hasChromeAPI: isExtension,
      protocol: window.location.protocol,
      userAgent: navigator.userAgent,
      extensionInfo: this.getExtensionInfo(),
    }
  }

  /**
   * 检查当前是否在油猴脚本环境中运行
   * @description 检测脚本是否运行在油猴/暴力猴等用户脚本管理器中
   * @returns {boolean} 是否为油猴脚本环境
   * @example
   * if (EnvironmentUtils.isUserScriptEnvironment()) {
   *   console.log('运行在油猴脚本环境中');
   * } else {
   *   console.log('运行在普通网页环境中');
   * }
   */
  static isUserScriptEnvironment(): boolean {
    const pageWindow = this.getTargetPageWindow()
    const scriptWindow = this.getScriptSandboxWindow()

    return typeof pageWindow !== 'undefined' && pageWindow !== scriptWindow
  }

  /**
   * 检查是否在浏览器扩展环境中运行
   * @description 检测脚本是否运行在浏览器扩展背景页或内容脚本中
   * @returns {boolean} 是否为浏览器扩展环境
   * @example
   * if (EnvironmentUtils.isBrowserExtensionEnvironment()) {
   *   // 扩展环境特有逻辑
   *   console.log('运行在浏览器扩展环境中');
   * }
   */
  static isBrowserExtensionEnvironment(): boolean {
    // 安全地检查 chrome API
    const hasChromeAPI = this.safeCheckChromeAPI()
    const hasBrowserAPI = this.safeCheckBrowserAPI()

    return hasChromeAPI || hasBrowserAPI
  }

  /**
   * 安全地检查 Chrome API 可用性
   */
  private static safeCheckChromeAPI(): boolean {
    try {
      // 使用 typeof 检查，避免直接访问可能不存在的属性
      return typeof chrome !== 'undefined'
        && (!!chrome.runtime || !!chrome.extension)
    }
    catch (error) {
      // 如果访问 chrome 对象时出错，说明不在扩展环境中
      return false
    }
  }

  /**
   * 安全地检查 Browser API 可用性（Firefox）
   */
  private static safeCheckBrowserAPI(): boolean {
    try {
      return typeof browser !== 'undefined'
        && !!browser.runtime
    }
    catch (error) {
      return false
    }
  }

  /**
   * 获取浏览器扩展类型
   * @description 检测具体的浏览器扩展类型
   * @returns {ExtensionType} 扩展类型
   * @example
   * const extType = EnvironmentUtils.getBrowserExtensionType();
   * if (extType === 'chrome') {
   *   // Chrome扩展特有逻辑
   * }
   */
  static getBrowserExtensionType(): ExtensionType {
    if (!this.isBrowserExtensionEnvironment()) {
      return 'none'
    }

    try {
      // 检查 Chrome
      if (typeof chrome !== 'undefined') {
        // 进一步检测具体类型
        if (this.isChromeExtension())
          return 'chrome'
        if (this.isEdgeExtension())
          return 'edge'
        return 'unknown'
      }

      // 检查 Firefox
      if (typeof browser !== 'undefined' && this.isFirefoxExtension()) {
        return 'firefox'
      }

      return 'unknown'
    }
    catch (error) {
      return 'unknown'
    }
  }

  /**
   * 检查是否为 Chrome 扩展
   */
  private static isChromeExtension(): boolean {
    try {
      return !!chrome.runtime
        && typeof chrome.runtime.getURL === 'function'
        && (chrome.runtime.id || '').length > 0
    }
    catch {
      return false
    }
  }

  /**
   * 检查是否为 Firefox 扩展
   */
  private static isFirefoxExtension(): boolean {
    try {
      return !!browser.runtime
        && typeof browser.runtime.getURL === 'function'
    }
    catch {
      return false
    }
  }

  /**
   * 检查是否为 Edge 扩展
   */
  private static isEdgeExtension(): boolean {
    try {
      // Edge 也使用 chrome API，但可以通过 userAgent 区分
      const isEdge = navigator.userAgent.includes('Edg/')
      return isEdge && !!chrome?.runtime
    }
    catch {
      return false
    }
  }

  /**
   * 获取扩展信息
   * @description 安全地获取浏览器扩展的详细信息
   * @returns {ExtensionInfo | null} 扩展信息，如果不在扩展环境中返回 null
   * @example
   * const extInfo = EnvironmentUtils.getExtensionInfo();
   * if (extInfo) {
   *   console.log('扩展ID:', extInfo.id);
   *   console.log('扩展类型:', extInfo.type);
   * }
   */
  static getExtensionInfo(): ExtensionInfo | null {
    if (!this.isBrowserExtensionEnvironment()) {
      return null
    }

    try {
      const type = this.getBrowserExtensionType()
      let id: string | undefined
      let version: string | undefined

      if (type === 'chrome' || type === 'edge') {
        id = chrome?.runtime?.id
        // 尝试获取 manifest 信息
        const manifest = chrome?.runtime?.getManifest?.()
        version = manifest?.version
      }
      else if (type === 'firefox') {
        // Firefox 扩展信息获取方式可能不同
        id = 'firefox-extension' // 占位符
      }

      return {
        type,
        id: id || 'unknown',
        version: version || 'unknown',
        isContentScript: this.isContentScriptEnvironment(),
        isBackgroundPage: this.isBackgroundPageEnvironment(),
      }
    }
    catch (error) {
      return {
        type: 'unknown',
        id: 'error',
        version: 'unknown',
        isContentScript: false,
        isBackgroundPage: false,
      }
    }
  }

  /**
   * 检查是否为内容脚本环境
   */
  private static isContentScriptEnvironment(): boolean {
    try {
      const scriptWindow = this.getScriptSandboxWindow()
      // 内容脚本可以访问 DOM 但受到限制
      return typeof scriptWindow !== 'undefined'
        && typeof document !== 'undefined'
        && this.isBrowserExtensionEnvironment()
    }
    catch {
      return false
    }
  }

  /**
   * 检查是否为后台页面环境
   */
  private static isBackgroundPageEnvironment(): boolean {
    try {
      const scriptWindow = this.getScriptSandboxWindow()

      // 后台页面通常没有 DOM 访问权限
      return typeof scriptWindow !== 'undefined'
        && (typeof document === 'undefined' || !document.documentElement)
        && this.isBrowserExtensionEnvironment()
    }
    catch {
      return false
    }
  }

  /**
   * 安全地使用扩展 API
   * @description 提供安全的扩展 API 调用封装
   * @param {ExtensionAPICall} apiCall - API 调用配置
   * @returns {Promise<any>} API 调用结果
   * @example
   * const result = await EnvironmentUtils.safeExtensionAPI({
   *   action: 'sendMessage',
   *   data: { type: 'test' }
   * });
   */
  static async safeExtensionAPI(apiCall: ExtensionAPICall): Promise<any> {
    if (!this.isBrowserExtensionEnvironment()) {
      throw new Error('不在浏览器扩展环境中，无法调用扩展 API')
    }

    try {
      const { action, data = {} } = apiCall

      switch (action) {
        case 'sendMessage':
          return await this.safeSendMessage(data)

        case 'getURL':
          return this.safeGetURL(data?.path)

        case 'getManifest':
          return this.safeGetManifest()

        default:
          throw new Error(`不支持的扩展 API 动作: ${action}`)
      }
    }
    catch (error: any) {
      throw new Error(`扩展 API 调用失败: ${error.message}`)
    }
  }

  /**
   * 安全地发送消息
   */
  private static async safeSendMessage(data: any): Promise<any> {
    return new Promise((resolve, reject) => {
      try {
        if (typeof chrome !== 'undefined' && chrome.runtime?.sendMessage) {
          chrome.runtime.sendMessage(data, (response) => {
            if (chrome?.runtime?.lastError) {
              reject(new Error(chrome.runtime.lastError.message))
            }
            else {
              resolve(response)
            }
          })
        }
        else if (typeof browser !== 'undefined' && browser.runtime?.sendMessage) {
          browser.runtime.sendMessage(data)
            .then(resolve)
            .catch(reject)
        }
        else {
          reject(new Error('扩展消息API不可用'))
        }
      }
      catch (error) {
        reject(error)
      }
    })
  }

  /**
   * 安全地获取扩展资源 URL
   */
  private static safeGetURL(path?: string): string {
    try {
      if (typeof chrome !== 'undefined' && chrome.runtime?.getURL) {
        return chrome.runtime.getURL(path || '')
      }
      else if (typeof browser !== 'undefined' && browser.runtime?.getURL) {
        return browser.runtime.getURL(path || '')
      }
      throw new Error('getURL API不可用')
    }
    catch (error: any) {
      throw new Error(`获取扩展资源URL失败: ${error.message}`)
    }
  }

  /**
   * 安全地获取扩展清单
   */
  private static safeGetManifest(): any {
    try {
      if (typeof chrome !== 'undefined' && chrome.runtime?.getManifest) {
        return chrome.runtime.getManifest()
      }
      // Firefox 可能需要不同的方式
      throw new Error('getManifest API不可用')
    }
    catch (error: any) {
      throw new Error(`获取扩展清单失败: ${error.message}`)
    }
  }

  /**
   * 检查页面是否加载了特定库
   * @description 检测页面中是否已加载指定的JavaScript库
   * @param {string} libraryName - 库名称（如 'jQuery', 'Vue', 'React'）
   * @returns {boolean} 是否已加载
   * @example
   * if (EnvironmentUtils.isLibraryLoadedInPage('Vue')) {
   *   console.log('页面已加载Vue.js');
   * }
   */
  static isLibraryLoadedInPage(libraryName: string): boolean {
    const pageWindow = this.getTargetPageWindow()

    const libraryChecks: Record<string, () => boolean> = {
      jQuery: () => !!(pageWindow.jQuery || pageWindow.$),
      Vue: () => !!pageWindow.Vue,
      React: () => !!pageWindow.React,
      Angular: () => !!pageWindow.angular,
      lodash: () => !!pageWindow._,
      moment: () => !!pageWindow.moment,
      axios: () => !!pageWindow.axios,
    }

    const checkFn = libraryChecks[libraryName]
    return checkFn ? checkFn() : false
  }

  /**
   * 获取页面已加载的库列表
   * @description 扫描页面中已加载的常见JavaScript库
   * @returns {string[]} 已加载的库名称数组
   * @example
   * const loadedLibraries = EnvironmentUtils.getPageLoadedLibraries();
   * console.log('页面已加载库:', loadedLibraries);
   */
  static getPageLoadedLibraries(): string[] {
    const libraries = [
      'jQuery',
      'Vue',
      'React',
      'Angular',
      'lodash',
      'moment',
      'axios',
      'Alpine',
      'Svelte',
      'Preact',
      'Ember',
    ]

    return libraries.filter(lib => this.isLibraryLoadedInPage(lib))
  }

  /**
   * 环境兼容性检查
   * @description 检查当前环境是否支持脚本运行所需功能
   * @returns {CompatibilityReport} 兼容性报告
   * @example
   * const compatibility = EnvironmentUtils.checkCompatibility();
   * if (!compatibility.isCompatible) {
   *   console.warn('环境不兼容:', compatibility.issues);
   * }
   */
  static checkCompatibility(): CompatibilityReport {
    const issues: string[] = []
    const warnings: string[] = []

    // 检查基本API支持
    if (typeof Promise === 'undefined') {
      issues.push('浏览器不支持 Promise')
    }

    if (typeof fetch === 'undefined') {
      warnings.push('浏览器不支持 fetch API，将使用 XMLHttpRequest 回退')
    }

    // 检查油猴API
    if (this.isUserScriptEnvironment()) {
      if (typeof GM_xmlhttpRequest === 'undefined') {
        warnings.push('油猴版本较旧，不支持 GM_xmlhttpRequest')
      }
    }

    // 检查存储支持
    if (typeof localStorage === 'undefined') {
      warnings.push('localStorage 不可用')
    }

    return {
      isCompatible: issues.length === 0,
      issues,
      warnings,
      environment: this.getExecutionEnvironment(),
    }
  }

  /**
   * 框架检测
   * }
   */
  static detectFramework(): FrameworkType[] {
    const detected: FrameworkType[] = []

    // React 检测
    if (window.React || document.querySelector('[data-reactroot]')) {
      detected.push(FrameworkType.React)
    }

    // Vue 检测
    if (window.Vue || document.querySelector('[data-v-app]')) {
      detected.push(FrameworkType.Vue)
    }

    // Angular 检测
    if (window.ng || document.querySelector('[ng-version]')) {
      detected.push(FrameworkType.Angular)
    }

    logger.debug(`${SYMBOLS.UI.SEARCH} 检测到框架: ${detected.join(', ') || '无'}`)
    return detected
  }

  /**
   * 检测剪贴板兼容性
   */
  static checkClipboardCompatibility(): boolean {
    return !!(navigator.clipboard?.write)
  }
}
